﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Common;
using System.Configuration;
using System.Data;

namespace WDA.Config.Database
{
	public class ConfigurationManager : IConfigurationManager
	{
		#region Properties
		public string ConnectionStringName { get; set; }
		#endregion      

		#region IConfigurationManager Members
		public IConfiguration GetConfiguration(string name, bool includeHosts)
		{
			ConnectionStringSettings connString = System.Configuration.ConfigurationManager.ConnectionStrings[ConnectionStringName];
			//TODO: add null-check here.
			DbProviderFactory dbFactory = DbProviderFactories.GetFactory(connString.ProviderName);

			using (IDbConnection conn = dbFactory.CreateConnection())
			{
				conn.ConnectionString = connString.ConnectionString;
				conn.Open();

				return GetConfiguration(conn, name, includeHosts);
			}			
		}

		private static List<IService> GetServices(IDbConnection conn, Host host)
		{
			using (IDbCommand cmd = conn.CreateCommand())
			{
				cmd.CommandText = "GetHostServices";
				cmd.CommandType = CommandType.StoredProcedure;

				cmd.AddInputParam("@HostId", host.Id);

				List<IService> results = new List<IService>();
				using (IDataReader rdr = cmd.ExecuteReader())
				{
					while (rdr.Read())
					{
                  string uri = rdr.IsDBNull(2) ? null : rdr.GetString(2);
                  string monitorUri = rdr.IsDBNull(3) ? null : rdr.GetString(3);
						int? basePort = null;
						if (!rdr.IsDBNull(7))
						{
							basePort = rdr.GetInt32(7);
						}
						Service newService = new Service(rdr.GetInt32(0), rdr.GetString(1), uri, monitorUri, rdr.GetString(4), rdr.GetString(5), rdr.GetString(6), basePort, host);
						results.Add(newService);
					}
				}
				return results;
			}
		}

		private static List<IHost> GetHosts(IDbConnection conn, int configId)
		{
			List<Host> interResults = new List<Host>();
			using (IDbCommand cmd = conn.CreateCommand())
			{
				cmd.CommandText = "GetHosts";
				cmd.CommandType = CommandType.StoredProcedure;

				cmd.AddInputParam("@ConfigurationId", configId);
				
				using (IDataReader rdr = cmd.ExecuteReader())
				{
					while (rdr.Read())
					{
                  string uri = rdr.IsDBNull(2) ? null : rdr.GetString(2);
                  string monitorUri = rdr.IsDBNull(3) ? null : rdr.GetString(3);
						string mgmtUri = rdr.IsDBNull(4) ? null : rdr.GetString(4);

						Host newHost = new Host(rdr.GetInt32(0), rdr.GetString(1), uri, monitorUri, mgmtUri);
						interResults.Add(newHost);
					}
				}				
			}
			List<IHost> results = new List<IHost>();
			foreach (Host h in interResults)
			{
				h.SetServices(GetServices(conn, h));
				results.Add(h);
			}
			return results;
		}

		private static IConfiguration GetConfiguration(IDbConnection conn, string name, bool includeHosts)
		{
			using (IDbCommand cmd = conn.CreateCommand())
			{
				cmd.CommandText = "GetConfiguration";
				cmd.CommandType = CommandType.StoredProcedure;

				cmd.AddInputParam("@Name", name);
				IDbDataParameter idParam = cmd.AddOutputParam("@Id", DbType.Int32);
				IDbDataParameter versionParam = cmd.AddOutputParam("@Version", DbType.Int64);

				cmd.ExecuteNonQuery();

				int configId = (int)idParam.Value;

				List<IHost> hosts = null;
				if (includeHosts)
				{
					hosts = GetHosts(conn, configId);
				}
				return new Configuration(configId, name, (long)versionParam.Value, hosts);				
			}
		}
		#endregion
	}
}
